﻿//www.codeOften.com
//Senthil Maruthaiappan - senips (at) gmail.com
//see license on http://www.codeplex.com/Jinglebell

using System;
using System.ComponentModel;
using System.Threading;
using CodeOften.Container;
using JingleBell.Interface;

namespace JingleBell.CommandShell
{
    [InstanceBehaviour(InstanceBehaviourType.AlwaysCreate)]
    public class CommandShellProcess : ICommandShellProcess
    {
        private readonly IProcessRunner _processRunner;
        private ProcessCaller _currentProcessCaller;

        public CommandShellProcess(IProcessRunner runner)
        {
            _processRunner = runner;
            CanGoNextProcess = false;
        }

        public IServices Services { get; set; }

        #region ICommandShellProcess Members

        public void CreateProcess(ISynchronizeInvoke sender, CommandItem item)
        {
            _currentProcessCaller = null;
            _currentProcessCaller = new ProcessCaller(sender);
            _currentProcessCaller.FileName = item.Command;
            if (string.IsNullOrEmpty(item.BuildCommand))
                _currentProcessCaller.Arguments = item.Arguments;
            else
                _currentProcessCaller.Arguments = item.Arguments + " && " + item.BuildCommand;
        }

        public void Start()
        {
            if (_currentProcessCaller != null)
            {
                CanGoNextProcess = false;
                HookEvents();
                _currentProcessCaller.Start();
            }
        }

        public IProcessListener Listener { get; set; }
        public bool CanGoNextProcess { get; set; }

        public void Cancel()
        {
            if (_currentProcessCaller != null)
                _currentProcessCaller.Cancel();
        }

        #endregion

        private void HookEvents()
        {
            if (_currentProcessCaller != null)
            {
                _currentProcessCaller.Completed += _currentProcessCaller_Completed;
                _currentProcessCaller.Cancelled += _currentProcessCaller_Cancelled;
                _currentProcessCaller.Failed += _currentProcessCaller_Failed;
                _currentProcessCaller.StdOutReceived += _currentProcessCaller_StdOutReceived;
                _currentProcessCaller.StdErrReceived += _currentProcessCaller_StdOutReceived;
            }
        }

        private void UnHookEvents()
        {
            if (_currentProcessCaller != null)
            {
                _currentProcessCaller.Completed -= _currentProcessCaller_Completed;
                _currentProcessCaller.Cancelled -= _currentProcessCaller_Cancelled;
                _currentProcessCaller.Failed -= _currentProcessCaller_Failed;
                _currentProcessCaller.StdOutReceived -= _currentProcessCaller_StdOutReceived;
                _currentProcessCaller.StdErrReceived -= _currentProcessCaller_StdOutReceived;
            }
        }


        private void _currentProcessCaller_StdOutReceived(object sender, DataReceivedEventArgs e)
        {
            if (Listener != null)
                Listener.ProcessResultOut(e.Text);
        }

        private void _currentProcessCaller_Failed(object sender, ThreadExceptionEventArgs e)
        {
            if (Listener != null)
                Listener.ProcessFail(e.Exception);
        }

        private void _currentProcessCaller_Cancelled(object sender, EventArgs e)
        {
            if (Listener != null)
                Listener.ProcessCancelled();
        }

        private void _currentProcessCaller_Completed(object sender, EventArgs e)
        {
            if (Listener != null)
                Listener.ProcessCompleted();
            CanGoNextProcess = true;
            _processRunner.GoNext();
        }
    }
}